package de.unistuttgart.iaaskpimonitoring.esper.processingmanagement;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.UpdateListener;

import de.unistuttgart.iaaskpimonitoring.esper.configurationmanagement.Configuration;
import de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.Filter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

public abstract class PPMProcessor {
	/**
	 * Initialization blocks
	 */
	private static DocumentBuilderFactory factory;

	static {
		PPMProcessor.factory = DocumentBuilderFactory.newInstance();
		factory.setValidating(true);
		factory.setNamespaceAware(true);
		factory.setIgnoringComments(true);
	}

	/**
	 * Class attributes
	 */
	private static int PPMProcessorLatestDistributedID = 0;

	/**
	 * Instance attributes
	 */
	private Filter filter;
	private String EPServiceURI = new String("engine"
			+ (++PPMProcessorLatestDistributedID));
	private EPServiceProvider EPService = EPServiceProviderManager
			.getProvider(EPServiceURI);
	private Map<String, MMOperatorNode> monitoringModelList;

	/**
	 * Public instance methods
	 */
	public void reinitializeEngine() {
		filter.stopFilter();
		EPService.initialize();
	}

	public void startPPMProcessing() {
		filter.startFilter();
		EPService.getEPAdministrator().startAllStatements();
	}

	public void stopPPMProcessing() {
		EPService.getEPAdministrator().stopAllStatements();
		filter.stopFilter();
	}

	public void closePPMProcessing() {
		EPService.getEPAdministrator().stopAllStatements();
		filter.closeFilter();
		filter = null;
	}

	public void stopProcessingOneMetric(String PPMName) {
		monitoringModelList.get(PPMName).getStatement().stop();
	}

	public void startProcessingOneMetric(String PPMName) {
		monitoringModelList.get(PPMName).getStatement().start();
	}

	public void registerListener(UpdateListener observer, String PPMName) {
		monitoringModelList.get(PPMName).getStatement().addListener(observer);
	}

	public void update(String PPMXMLFile) {
		reinitializeEngine();
		createMModelList(PPMXMLFile);
	}

	/**
	 * Private instance method
	 */
	private void createMModelList(String PPMXMLFile)
			throws ParserConfigurationException, IOException, SAXException,
			ClassNotFoundException, InstantiationException {
		EPAdministrator admin = EPService.getEPAdministrator();

		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(new File(PPMXMLFile));
		NodeList calculationFormulas = doc
				.getElementsByTagNameNS(
						"http://kpimonitoring.iaas.uni-stuttgart.de/2008/ppmCalculationFormula",
						"ppmCalculationFormula");

		monitoringModelList = new HashMap<String, MMOperatorNode>();

		for (int i = 0; i < calculationFormulas.getLength(); i++) {
			Element root = (Element) calculationFormulas.item(i);
			Element attachmentsElement = (Element) root.getNextSibling();
			Element rootElement4Calculation = (Element) root.getFirstChild();
			monitoringModelList.put(new String(root.getAttribute("name")),
					NodeFactoryManager.getInstance(
							rootElement4Calculation.getLocalName()).createNode(
							rootElement4Calculation, attachmentsElement, null, EPService));
		}

		// Creation of high level events wearing the name of the metric and that
		// are going to be listened to (by listeners of the GUI)
		for (String key : monitoringModelList.keySet()) {
			MMOperatorNode Op = monitoringModelList.get(key);
			String statString = new String("INSERT INTO " + key
					+ " SELECT * FROM " + Op.getOutputStreamName());
			EPStatement stat = admin.createEPL(statString);
		}

	}


	/**
	 * Constructors
	 */
	public PPMProcessor(Configuration cfg, String PPMXMLFile) {
		filter = new Filter(cfg, EPServiceURI);
		createMModelList(PPMXMLFile);
		startPPMProcessing();
	}
	
}
